package com.xlh.service.conclude.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.xlh.common.ResultEnum;
import com.xlh.constant.ConcludeContant;
import com.xlh.dao.conclude.ext.ConcludeMapperExt;
import com.xlh.dao.conclude.helper.*;
import com.xlh.dto.conclude.ConcludeCheckDTO;
import com.xlh.dto.conclude.ConcludeDTO;
import com.xlh.dto.conclude.ConcludeUpPublicDTO;
import com.xlh.dto.course.CourseBasicDTO;
import com.xlh.exception.common.BadRequestException;
import com.xlh.exception.common.GlobalException;
import com.xlh.job.ConcludeRefSysTask;
import com.xlh.param.conclude.ConcludeAddParam;
import com.xlh.param.conclude.ConcludeCopyParam;
import com.xlh.param.conclude.ConcludeUpdateParam;
import com.xlh.pojo.conclude.*;
import com.xlh.service.conclude.ConcludeService;
import com.xlh.service.course.CourseService;
import com.xlh.util.BeanUtil;
import com.xlh.vo.conclude.ConcludeDetailsVO;
import com.xlh.vo.conclude.ConcludeListInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author cfz
 */
@Service
public class ConcludeServiceImpl implements ConcludeService {

    @Autowired
    private ConcludeMapperHelper concludeMapperHelper;

    @Autowired
    private ConcludeMapperExt concludeMapperExt;
    /**
     * 课程目标表
     */
    @Autowired
    private ConcludeCourseMapperHelper concludeCourseMapperHelper;

    /**
     * 考核项表
     */
    @Autowired
    private ConcludeCheckMapperHelper concludeCheckMapperHelper;

    /**
     * 考核分项表
     */
    @Autowired
    private ConcludeCheckSubMapperHelper concludeCheckSubMapperHelper;

    @Autowired
    private CourseService courseService;

    @Autowired
    private ConcludeSubCourseMapperHelper concludeSubCourseMapperHelper;

    @Autowired
    private ConcludeRefSysTask concludeRefSysTask;



    @Override
    public List<ConcludeListInfoVO> list(Long courseId) {

        List<ConcludeListInfoVO> concludeListInfoVOS = concludeMapperExt.findConcludeAndStuCount(courseId);

        return concludeListInfoVOS;
    }

    @Override
    public Long add(ConcludeAddParam concludeAddParam) {

        ConcludeDTO concludeDTO = BeanUtil.transform(ConcludeDTO.class, concludeAddParam);
        String checkResult = checkParam(concludeDTO);
        if(StrUtil.isNotBlank(checkResult)){
            throw new GlobalException(ResultEnum.UNIQUE_NAME);
        }
        if(ObjectUtil.isNull(concludeAddParam.getThresholdValue())){
            concludeAddParam.init();
        }
        Conclude conclude = BeanUtil.transform(Conclude.class, concludeAddParam);
        Boolean insertResult = concludeMapperHelper.insert(conclude);

        if(insertResult == false){
            throw new GlobalException(ResultEnum.SERVER_ERROR);
        }
        return conclude.getId();
    }

    @Override
    @Transactional
    public void copy(ConcludeCopyParam concludeCopyParam) {

        ConcludeDTO concludeDTO = BeanUtil.transform(ConcludeDTO.class, concludeCopyParam);
        Long sourceId = concludeDTO.getId();
        Conclude conclude = concludeMapperHelper.get(sourceId);
        if(ObjectUtil.isNull(conclude)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CONCLUDE);
        }
        concludeDTO.setIconValue(String.valueOf(RandomUtil.randomInt(1,4))).setIsPublish(false).clearId() ;
        ConcludeAddParam concludeAddParam = BeanUtil.transform(ConcludeAddParam.class, concludeDTO);
        concludeAddParam.setCourseId(conclude.getCourseId());
        Long concludeId = add(concludeAddParam);
        concludeDTO.setId(concludeId);

        // 添加成功执行copy
        // 课程目标信息
        List<ConcludeCourse> concludeCourses = concludeCourseMapperHelper.findByCondition(sourceId);

        // 课程和考核分项的对应关系
        List<Long> conCourseIds = concludeCourses.stream().map(ConcludeCourse::getId).collect(Collectors.toList());
        List<ConcludeSubCourse> concludeSubCourses = Lists.newArrayList();
        if(CollectionUtil.isNotEmpty(conCourseIds)){
            concludeSubCourses = concludeSubCourseMapperHelper.findByCourseId(conCourseIds);
        }

        if(CollectionUtil.isNotEmpty(concludeCourses)){
            // 1. 插入课程目标信息
            for (ConcludeCourse concludeCourse : concludeCourses) {

                concludeCourse.setConcludeId(concludeDTO.getId());
                Long oldCourseId = concludeCourse.getId();
                concludeCourse.setId(null);
                concludeCourseMapperHelper.insert(concludeCourse);
                Long newCourseId = concludeCourse.getId();

                if(CollectionUtil.isNotEmpty(concludeSubCourses)){
                    replaceCourseId(concludeSubCourses, oldCourseId, newCourseId);
                }

            }
        }
        // 考核项信息
        List<ConcludeCheck> concludeChecks = concludeCheckMapperHelper.findByCondition(sourceId);
        if(CollectionUtil.isNotEmpty(concludeChecks)){

            List<Long> checkIds = concludeChecks.stream().map(ConcludeCheck::getId).collect(Collectors.toList());
            List<ConcludeCheckSub> concludeCheckSubs = concludeCheckSubMapperHelper.findByCheckIds(checkIds);
            List<ConcludeCheckDTO> lists = mergeCheckDtos(concludeChecks, concludeCheckSubs);
            // 2. 插入考核项信息
            for (ConcludeCheckDTO concludeCheckDTO : lists) {
                // 插入考核项
                ConcludeCheck concludeCheck = concludeCheckDTO.getConcludeCheck();
                concludeCheck.setId(null);
                concludeCheck.setConcludeId(concludeDTO.getId());
                concludeCheckMapperHelper.insert(concludeCheck);
                // 插入考核分项
                Long checkId = concludeCheck.getId();
                List<ConcludeCheckSub> concludeSubs = concludeCheckDTO.getConcludeCheckSubs();
                if(CollectionUtil.isNotEmpty(concludeSubs)){

                    for (ConcludeCheckSub concludeSub : concludeSubs) {

                        concludeSub.setCheckId(checkId);
                        Long oldSubId = concludeSub.getId();
                        concludeSub.setId(null);
                        concludeCheckSubMapperHelper.insert(concludeSub);
                        Long newSubId = concludeSub.getId();
                        replaceSubId(concludeSubCourses, oldSubId, newSubId);
                    }
                }
            }
        }
        // 插入考核分项和课程中间的关系表
        concludeSubCourseMapperHelper.insertBatch(concludeSubCourses);

    }

    /**
     * 替换关系表中的考核分项ID
     * @param concludeSubCourses
     * @param oldSubId
     * @param newSubId
     */
    private void replaceSubId(List<ConcludeSubCourse> concludeSubCourses, Long oldSubId, Long newSubId) {

        for (ConcludeSubCourse concludeSubCours : concludeSubCourses) {
            concludeSubCours.setId(null);
            Long checkSubId = concludeSubCours.getCheckSubId();
            if(checkSubId.compareTo(oldSubId) == 0){
                concludeSubCours.setCheckSubId(newSubId);
            }
        }
    }

    /**
     * 替换关系表中的courseId
     * @param concludeSubCourses
     * @param oldCourseId
     * @param newCourseId
     */
    private void replaceCourseId(List<ConcludeSubCourse> concludeSubCourses, Long oldCourseId, Long newCourseId) {

        for (ConcludeSubCourse concludeSubCours : concludeSubCourses) {
            concludeSubCours.setId(null);
            Long conCourseId = concludeSubCours.getConCourseId();
            if(conCourseId.compareTo(oldCourseId) == 0){
                concludeSubCours.setConCourseId(newCourseId);
            }
        }
    }

    @Override
    @Transactional
    public String delete(Long id) {

        // 1. 删除达成度目标
        concludeMapperHelper.delete(id);
        // 2. 删除相关课程目标信息
        concludeCourseMapperHelper.delete(id);
        // 3. 删除考核项信息
        List<ConcludeCheck> concludeChecks = concludeCheckMapperHelper.findByCondition(id);
        if(CollectionUtil.isNotEmpty(concludeChecks)){
            concludeCheckMapperHelper.delete(concludeChecks);
            // 4. 删除考核分项信息
            List<Long> checkIds = concludeChecks.stream().map(ConcludeCheck::getConcludeId).collect(Collectors.toList());
            List<ConcludeCheckSub> concludeCheckSubs = concludeCheckSubMapperHelper.findByCheckIds(checkIds);
            if(CollectionUtil.isNotEmpty(concludeCheckSubs)){
                concludeCheckSubMapperHelper.delete(concludeCheckSubs);
            }
        }

        return null;
    }

    @Override
    public ConcludeDetailsVO details(Long id) {

        if(ObjectUtil.isNull(id)){
            throw new GlobalException(ResultEnum.NOT_FOUND_COURSE);
        }
        ConcludeDetailsVO concludeDetailsVO  = concludeMapperExt.getConcludeById( id );
        if(ObjectUtil.isNull(concludeDetailsVO)){
            throw new GlobalException(ResultEnum.NOT_FOUND_COURSE);
        }
        CourseBasicDTO course = courseService.getCourse(concludeDetailsVO.getCourseId());
        concludeDetailsVO.setCourseName(course.getName());
        // 获取缓存中的成绩
        BigDecimal score = (BigDecimal)ConcludeScoreServiceImpl.timeChache.get(id + ConcludeContant.PROPERTY_SCORE);
        if(ObjectUtil.isNotNull(score)){
            concludeDetailsVO.setScore(score.toPlainString());
            ConcludeScoreServiceImpl.timeChache.remove(id + ConcludeContant.PROPERTY_SCORE);
        }
        return concludeDetailsVO;
    }


    @Override
    public void ispublic(ConcludeUpPublicDTO concludeUpPublicDTO) {

        Conclude conclude = BeanUtil.transform(Conclude.class, concludeUpPublicDTO);
        // 如果状态为打开状态则关闭其他考核项状态
        if(concludeUpPublicDTO.getIsPublish() == true){

            Conclude concludeRecord = concludeMapperHelper.get(conclude.getId());
            Long courseId = concludeRecord.getCourseId();
            Conclude upRecord = new Conclude();
            upRecord.setCourseId(courseId);
            upRecord.setIsPublish(false);
            concludeMapperHelper.updateByCourseId(upRecord);
        }
        concludeMapperHelper.update( conclude );
    }

    @Override
    public void update(ConcludeUpdateParam concludeUpdateParam) {

        ConcludeDTO concludeDTO = BeanUtil.transform(ConcludeDTO.class, concludeUpdateParam);
        if(ObjectUtil.isNull(concludeDTO.getId())){
            throw new GlobalException(ResultEnum.NOT_FOUND_CONCLUDE);
        }
        // 检查记录是否存在
        Conclude record = concludeMapperHelper.get(concludeDTO.getId());
        if(ObjectUtil.isNull(record)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CONCLUDE);
        }
        // 检查名称唯一
        if(StrUtil.isNotBlank(concludeDTO.getName())){
            concludeDTO.setCourseId(record.getCourseId());
            checkParam(concludeDTO);
        }
        // 修改负责人
        if(ObjectUtil.isNotNull(concludeDTO.getPrincipal())){
            if(StrUtil.isBlank(concludeDTO.getPrincipal())){
                throw new GlobalException(ResultEnum.ERROR_PRINCIPAL_IS_EMPTY);
            }
        }
        Conclude conclude = BeanUtil.transform(Conclude.class, concludeDTO);
        concludeMapperHelper.update(conclude);
    }

    @Override
    public void exeUpdate(Long concludeId) {

        if(ObjectUtil.isNotNull(concludeId)){
            concludeRefSysTask.updateToConclude(concludeId);
        }
    }

    /**
     * 将考核项和考核分项重新组装
     * @param concludeChecks
     * @param concludeCheckSubs
     * @return
     */
    public List<ConcludeCheckDTO> mergeCheckDtos(List<ConcludeCheck> concludeChecks, List<ConcludeCheckSub> concludeCheckSubs) {

        List<ConcludeCheckDTO> concludeCheckDTOs = Lists.newArrayList();
        Map<Long, List<ConcludeCheckSub>> checkIdMap = concludeCheckSubs.stream().collect(Collectors.groupingBy(ConcludeCheckSub::getCheckId));
        for (ConcludeCheck concludeCheck : concludeChecks) {
            ConcludeCheckDTO concludeCheckDTO = new ConcludeCheckDTO();
            List<ConcludeCheckSub> concludeCheckSubsByCheckId = checkIdMap.get(concludeCheck.getId());
            concludeCheckDTO.setConcludeCheck(concludeCheck);
            concludeCheckDTO.setConcludeCheckSubs(concludeCheckSubsByCheckId);
            concludeCheckDTOs.add(concludeCheckDTO);
        }
        return  concludeCheckDTOs;
    }

    /**
     * 校验参数信息是否正确
     * @param concludeDTO
     * @return
     */
    private String checkParam(ConcludeDTO concludeDTO) {
        // 校验达成度名称不可重复
        String name = concludeDTO.getName();
        List<Conclude> list = concludeMapperHelper.findByCondition(concludeDTO.getCourseId(), name);
        if(CollectionUtil.isNotEmpty(list)){
            throw new BadRequestException("达成度名称不可重复");
        }
        return null;
    }


}
